#pragma once 

#include<iostream>
#include<string>
#include<vector>
#include<fstream>
#include<memory>
#include<sys/stat.h>
#include<experimental/filesystem>
#include<jsoncpp/json/json.h>
#include "bundle.h"

namespace cloud
{
    namespace fs = std::experimental::filesystem;   //简化命名空间

    class FileUtil{
        private:
            std::string _fliename;
        public:
            FileUtil(const std::string &name):_fliename(name){}

            bool Remove()
            {
                if(this->Exists() == false)
                    return false;
                remove(_fliename.c_str());
                return true;
            }


            // size_t FileSize();
            int64_t FileSize()     //返回文件大小
            {
                struct stat st;
                if(stat(_fliename.c_str(), &st) < 0)
                {
                    std::cout<<"get file size failed\n";
                    return -1;
                }
                return st.st_size;
            }
            time_t LastAtime()   //最后访问时间
            {
                struct stat st;
                if(stat(_fliename.c_str(), &st) < 0)
                {
                    std::cout<<"get file last Access time failed\n";
                    return -1;
                }
                return st.st_atime;
            }
            time_t LastMTime()
            {
                struct stat st;
                if(stat(_fliename.c_str(), &st) < 0)
                {
                    std::cout<<"get file last Modify time failed\n";
                    return -1;
                }
                return st.st_mtime;
            }
            
            //
            std::string FileName()
            {
                //  ./abc/bef/hello.txt -> hello.txt
                size_t pos = _fliename.find_last_of('/');
                if(pos == std::string::npos)
                {
                    return _fliename;
                }
                return _fliename.substr(pos+1); 
            }

            //获得指定位置的文件内容
            bool GetPosLen(std::string *content, size_t pos, size_t len)
            {
                std::ifstream ifs;
                ifs.open(_fliename, std::ios::binary);  //二进制形式打开
                if(ifs.is_open() == false)
                {
                    std::cout<<"open file error\n";
                    return false;
                }
                size_t fsize = FileSize();
                if(pos + len > fsize)
                {
                    std::cout<<" read file len is error\n";
                    return false;
                }
                ifs.seekg(pos, std::ios::beg);
                content->resize(len);
                ifs.read(&(*content)[0], len);
                if(ifs.good() == false)
                {
                    std::cout<< " get file content failed\n";
                    return false;
                }
                ifs.close();
                return true;
                    
            }
            bool GetContent(std::string *content)
            {
                size_t fsize = FileSize();
                return GetPosLen(content, 0, fsize);
            }

            bool SetContent(const std::string *content)
            {
                std::ofstream ofs;
                ofs.open(_fliename, std::ios::binary);
                if(ofs.is_open() == false)
                {
                    std::cout<<"write file error\n";
                    return false;
                }
                ofs.write(&(*content)[0], content->size());
                if(ofs.good() == false)
                {
                    std::cout<<"writ file content failed\n";
                    return false;
                }
                ofs.close();
                return true;
            }
            
            //将数据压缩至指定的压缩包文件
            bool Compress(const std::string &packname)
            {
                //1.获取源文件数据
                std::string body;
                if(GetContent(&body) == false)
                {
                    std::cout<<"compress get file error\n";
                    return false;
                }
                //2.对数据进行压缩
                std::string packed = bundle::pack(bundle::LZIP, body); //以lzip格式压缩文件
                //3.将压缩的数据存储到压缩包文件中
                FileUtil fu(packname);
                if(fu.SetContent(&packed) == false)
                {
                    std::cout<<" compress writ packed failed\n";
                    return false;
                }
                return true;
            }
            //将数据解压到指定的文件
            bool UnCompress(const std::string &filename)
            {
                //将当前压缩包数据都取出来
                std::string  body;
                if(GetContent(&body) == false)
                {
                    std::cout<<" uncompress get file content failed\n";
                    return false;
                }
                //对数据进行解压缩
                std::string unpacked = bundle::unpack(body);
                //解压后的数据写入文件
                FileUtil fu(filename);
                if(fu.SetContent(&unpacked) == false)
                {
                    std::cout<<" uncompress write file failed\n";
                    return false;
                }
                return true;
            }

            /*遍历文件的功能：man 3 scandir
                c++17的 Filesystem 里面有方便操作目录的
            */   
            bool Exists()  //检查一个文件是否存在
            {
                return fs::exists(_fliename);   
            }

            //创建目录
            bool CreateDirectory()
            {
                if(Exists()) return true;
                    return fs::create_directories(_fliename);   
            }


            //遍历文件（非目录文件）
            bool ScanDirectory(std::vector<std::string> *arry)
            {
                for(auto &p:fs::directory_iterator(_fliename))
                {
                    if(fs::is_directory(p) == true)
                        continue;
                    
                    // relative_path 带有路径的文件名
                    arry->push_back(fs::path(p).relative_path().string());
                }
                return true;
            }

    };

    class JsonUtil
    {
        public:
            //序列化,  将Josn数据转换成序列化数据，传给网上
            static bool Serialize(const Json::Value &root, std::string *str)
            {
                Json::StreamWriterBuilder swb;
                std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());

                std::stringstream ss;
                sw->write(root, &ss);
                *str = ss.str();

                return true;
            }

            //反序列化   将网上获得的序列化数据，转化成看得懂的json数据
            static bool UnSerialize(const std::string &str, Json::Value *root)
            {
                Json::CharReaderBuilder crb;
                std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
                std::string err;
                bool ret = cr->parse(str.c_str(), str.c_str()+str.size(), root, &err);  //将数据写到Json中
                if(ret == false){
                    std::cout<<"parse error: "<<err<<std::endl;
                    return false;
                }
                return true;

            }
    };

}

